package com.tansun.easycare.rule.utils;

import java.io.IOException;
import java.io.StringWriter;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

import com.tansun.rule.utils.MClass;
import com.tansun.rule.utils.MField;

/**
 * 请求报文中map和xml的相互转换 ljt 20191227
 */
public class RuleMapAndXmlUtils {

    /**
     * 将入参xml解析并与metaMap进行填充返回insertMap
     *
     * @param metaMap
     * @return
     */
    public static Map<String, Object> xmlCoverMap(String xml, Map<String, MClass> metaMap) throws Exception {
        Map<String, Object> insertMap = new HashMap<>();
        Document document = DocumentHelper.parseText(xml);
        Element rootElement = document.getRootElement();
        createInsertMap(rootElement, metaMap, insertMap);
        return insertMap;
    }

    private static void createInsertMap(Element element, Map<String, MClass> metaMap, Map<String, Object> insertMap) throws ParseException {
        MClass mClass = metaMap.get(element.getName());
        List<Attribute> attributes = element.attributes();
        if (attributes != null && attributes.size() > 0) {//证明该元素有属性
            Map<String, Object> sunMap = new HashMap<>();
            insertMap.put(element.getName(), sunMap);
            createAttrMapByMateClassData(element.getName(), mClass.getName(), element, sunMap, metaMap);
        }

        List<Element> elements = element.elements();
        if (elements != null && elements.size() > 0) {//证明该元素下有子元素
            for (Element ele : elements) {
                createInsertMap(ele, metaMap, insertMap);//递归解析xml
            }
        }
    }

    private static void createAttrMapByMateClassData(String name, String mclassName, Element element, Map<String, Object> sunMap, Map<String, MClass> metaMap) throws ParseException {
        if (element != null) {
            Set<String> set = metaMap.get(mclassName).getFieldMap().keySet();
            Iterator<String> iterator = set.iterator();
            while (iterator.hasNext()) {
                String fieldKey = iterator.next();
                MField mField = metaMap.get(mclassName).getFieldMap().get(fieldKey);
                Attribute attribute = element.attribute(mField.getName());
                if (attribute != null) {
                    sunMap.put(mField.getName(), createObject(mField, attribute.getValue()));
                }else {
                    sunMap.put(mField.getName(),mField.getDefaultValue());//入参没有的，获取默认值
                }
            }
        }
    }

    private static Object createObject(MField mField, String attrValue) throws ParseException {
        if (attrValue != null) {
            if ("String".equalsIgnoreCase(mField.getType())) {
                return attrValue;
            } else if ("Long".equalsIgnoreCase(mField.getType())) {
                return "".equals(attrValue) ? 0L : Long.parseLong(attrValue);
            } else if ("Double".equalsIgnoreCase(mField.getType())) {
                return "".equals(attrValue) ? 0.0D : Double.parseDouble(attrValue);
            } else if ("Integer".equalsIgnoreCase(mField.getType())) {
                return "".equals(attrValue) ? 0 : Integer.parseInt(attrValue);
            } else if ("FLoat".equalsIgnoreCase(mField.getType())) {
                return "".equals(attrValue) ? 0.0F : Float.parseFloat(attrValue);
            } else if ("Date".equalsIgnoreCase(mField.getType())) {
                return attrValue;
            } else if ("Boolean".equalsIgnoreCase(mField.getType())) {
                return !"true".equalsIgnoreCase(attrValue) && !"1".equalsIgnoreCase(attrValue) && !"y".equalsIgnoreCase(attrValue) && !"yes".equalsIgnoreCase(attrValue) ? Boolean.FALSE : Boolean.TRUE;
            } else {
                return null;
            }
        } else if ("String".equalsIgnoreCase(mField.getType())) {
            return "";
        } else if ("Long".equalsIgnoreCase(mField.getType())) {
            return null;
        } else if ("Double".equalsIgnoreCase(mField.getType())) {
            return null;
        } else if ("Integer".equalsIgnoreCase(mField.getType())) {
            return null;
        } else if ("Float".equalsIgnoreCase(mField.getType())) {
            return null;
        } else if ("Date".equalsIgnoreCase(mField.getType())) {
            return mField.getDefaultValue();
        } else {
            return "Boolean".equalsIgnoreCase(mField.getType()) ? false : null;
        }
    }

    /**
     * 规则计算执行完之后，将insertMap里面的值填充到xml报文格式中。
     * @param insertMap
     * @param xml
     * @return
     * @throws DocumentException
     */
    public static  String mapCoverXml(Map<String, Object> insertMap, String xml) throws DocumentException{
        Document newDocument = DocumentHelper.createDocument();
       Document document = DocumentHelper.parseText(xml);
        Element rootElement = document.getRootElement();
        Element root = newDocument.addElement(rootElement.getName());
        createXmlByInsertMap(rootElement,root,insertMap);

        StringWriter writer = new StringWriter();
        try {
            OutputFormat format =  OutputFormat.createPrettyPrint();
            format.setEncoding("UTF-8");
            XMLWriter output = new XMLWriter(writer,format);
            output.write(newDocument);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return writer.toString();
    }

    private static void createXmlByInsertMap(Element element,Element root,Map<String,Object> insertMap){
        List<Attribute> attributes = element.attributes();
        if(attributes!=null&&attributes.size()>0){
            String elementName = element.getName();
            Map<String,Object> attMap = (Map<String,Object>)insertMap.get(elementName);
            for(Attribute attribute : attributes){
                root.addAttribute(attribute.getName(),(String)attMap.get(attribute.getName())); }
        }
        //递归赋值
        List<Element> elements = element.elements();
        if(elements!=null&&elements.size()>0){
            for(Element ele : elements){
                Element newEle = root.addElement(ele.getName());
                createXmlByInsertMap(ele,newEle,insertMap);
            }
        }
    }
}
